import os
import threading
import time
import queue
import speech_recognition as sr
import pyttsx3
import re
import sys
from pathlib import Path
from datetime import datetime, timedelta

# Add parent directory to path to import from other modules
sys.path.append(str(Path(__file__).parent.parent.parent))

from database.db_connection import execute_query, get_redis_connection
from backend.utils.logger import setup_logger

# Set up logger
logger = setup_logger('voice_assistant')

class VoiceAssistant:
    def __init__(self, language='zh-CN'):
        """
        Initialize the voice assistant.
        
        Args:
            language (str): Language code for speech recognition. Default is 'zh-CN' (Chinese).
        """
        self.language = language
        self.recognizer = sr.Recognizer()
        
        try:
            # 初始化语音引擎
            logger.info("正在初始化语音引擎...")
            self.engine = pyttsx3.init()
            
            # 配置语音引擎
            voices = self.engine.getProperty('voices')
            logger.info(f"可用的语音: {[voice.id for voice in voices]}")
            
            # 尝试找到匹配语言的语音
            voice_found = False
            for voice in voices:
                logger.info(f"检查语音: {voice.id}")
                if language[:2].lower() in voice.id.lower():
                    self.engine.setProperty('voice', voice.id)
                    voice_found = True
                    logger.info(f"已选择语音: {voice.id}")
                    break
            
            if not voice_found:
                logger.warning(f"未找到匹配语言 {language} 的语音，使用默认语音")
            
            # 设置语音速率和音量
            self.engine.setProperty('rate', 150)
            self.engine.setProperty('volume', 1.0)
            
            # 测试语音引擎
            logger.info("测试语音引擎...")
            self.engine.say("语音系统初始化完成")
            self.engine.runAndWait()
            
        except Exception as e:
            logger.error(f"语音引擎初始化失败: {e}")
            self.engine = None
        
        self.is_running = False
        self.command_queue = queue.Queue()
        self.response_queue = queue.Queue()
        
        # 初始化麦克风
        try:
            logger.info("正在初始化麦克风...")
            with sr.Microphone() as source:
                self.recognizer.adjust_for_ambient_noise(source, duration=1)
                logger.info("麦克风初始化成功")
        except Exception as e:
            logger.error(f"麦克风初始化失败: {e}")
        
        # 初始化 Redis 连接
        try:
            self.redis = get_redis_connection()
            logger.info("Redis 连接已建立")
        except Exception as e:
            logger.error(f"Redis 连接失败: {e}")
            self.redis = None
    
    def start(self, command_callback=None):
        """
        Start the voice assistant in a separate thread.
        
        Args:
            command_callback (callable): Callback function to call when a command is recognized.
                The callback should accept the recognized text as a parameter.
        """
        if self.is_running:
            logger.warning("语音助手已在运行")
            return
        
        if self.engine is None:
            logger.error("语音引擎未正确初始化，无法启动语音助手")
            return
        
        self.is_running = True
        self.command_callback = command_callback
        
        try:
            # 启动监听线程
            logger.info("正在启动语音监听线程...")
            self.listen_thread = threading.Thread(target=self._listen_loop)
            self.listen_thread.daemon = True
            self.listen_thread.start()
            
            # 启动语音合成线程
            logger.info("正在启动语音合成线程...")
            self.speak_thread = threading.Thread(target=self._speak_loop)
            self.speak_thread.daemon = True
            self.speak_thread.start()
            
            logger.info("语音助手启动成功")
            self.speak("语音助手已启动，可以开始使用")
            
        except Exception as e:
            logger.error(f"启动语音助手时出错: {e}")
            self.is_running = False
            raise
    
    def stop(self):
        """Stop the voice assistant."""
        self.is_running = False
        logger.info("Voice assistant stopped")
    
    def speak(self, text):
        """
        Queue text to be spoken.
        
        Args:
            text (str): The text to speak.
        """
        self.response_queue.put(text)
    
    def _listen_loop(self):
        """Main listening loop for the voice assistant."""
        try:
            with sr.Microphone() as source:
                # Adjust for ambient noise
                self.recognizer.adjust_for_ambient_noise(source, duration=1)
                logger.info("Voice assistant is listening...")
                
                while self.is_running:
                    try:
                        # Listen for speech
                        audio = self.recognizer.listen(source, timeout=1, phrase_time_limit=5)
                        
                        # Recognize speech
                        text = self.recognizer.recognize_google(audio, language=self.language)
                        logger.info(f"Recognized: {text}")
                        
                        # Process the recognized text
                        self._process_command(text)
                        
                        # Call the callback function if provided
                        if self.command_callback:
                            self.command_callback(text)
                    
                    except sr.WaitTimeoutError:
                        # Timeout, continue listening
                        continue
                    except sr.UnknownValueError:
                        # Speech was unintelligible
                        logger.debug("Could not understand audio")
                        continue
                    except sr.RequestError as e:
                        # API was unreachable or unresponsive
                        logger.error(f"Error with the speech recognition service: {e}")
                        time.sleep(1)
                    except Exception as e:
                        logger.error(f"Error in listening loop: {e}")
                        time.sleep(1)
        
        except Exception as e:
            logger.error(f"Error initializing microphone: {e}")
            self.is_running = False
    
    def _speak_loop(self):
        """Main speaking loop for the voice assistant."""
        while self.is_running:
            try:
                # Get text from the queue with a timeout
                text = self.response_queue.get(timeout=1)
                
                # Speak the text
                logger.info(f"Speaking: {text}")
                self.engine.say(text)
                self.engine.runAndWait()
                
                # Mark the task as done
                self.response_queue.task_done()
            
            except queue.Empty:
                # Queue is empty, continue
                continue
            except Exception as e:
                logger.error(f"Error in speaking loop: {e}")
                time.sleep(1)
    
    def _process_command(self, text):
        """
        Process a voice command.
        
        Args:
            text (str): The recognized text to process.
        """
        try:
            # Convert text to lowercase for easier matching
            text_lower = text.lower()
            
            # Check for attendance-related commands
            if any(keyword in text_lower for keyword in ['打卡', '签到', '考勤']):
                self.speak("请面向摄像头，系统将为您进行人脸识别打卡")
            
            # Check for leave request commands
            elif any(keyword in text_lower for keyword in ['请假', '休假', '病假', '事假']):
                self._handle_leave_request(text)
            
            # Check for policy inquiry commands
            elif any(keyword in text_lower for keyword in ['制度', '规定', '政策', '查询']):
                self._handle_policy_inquiry(text)
            
            # General help command
            elif any(keyword in text_lower for keyword in ['帮助', '怎么用', '使用说明']):
                self._provide_help()
            
            # Unknown command
            else:
                self.speak("抱歉，我没有理解您的请求。您可以尝试打卡、请假或查询公司制度。")
        
        except Exception as e:
            logger.error(f"Error processing command: {e}")
            self.speak("处理您的请求时出现错误，请稍后再试。")
    
    def _handle_leave_request(self, text):
        """
        Handle a leave request command.
        
        Args:
            text (str): The recognized text containing the leave request.
        """
        try:
            # Extract leave type
            leave_type = "other"  # Default
            if '病假' in text:
                leave_type = "sick"
            elif '事假' in text:
                leave_type = "personal"
            elif '年假' in text or '休假' in text:
                leave_type = "vacation"
            
            # Extract duration
            days = 1  # Default is 1 day
            day_match = re.search(r'(\d+)\s*[天日]', text)
            if day_match:
                days = int(day_match.group(1))
            
            # Extract start date (default to tomorrow)
            start_date = datetime.now().date() + timedelta(days=1)
            
            # Extract reason
            reason = text
            
            # Confirm the leave request details
            confirmation = f"您要申请{days}天{self._get_leave_type_name(leave_type)}，从{start_date.strftime('%Y年%m月%d日')}开始，是这样吗？"
            self.speak(confirmation)
            
            # In a real application, we would wait for confirmation before proceeding
            # For now, we'll just submit the request
            
            # Store the leave request in the database
            employee_id = "temp_employee"  # In a real app, this would be the recognized employee
            end_date = start_date + timedelta(days=days-1)
            
            query = """
                INSERT INTO leave_requests 
                (employee_id, leave_type, start_date, end_date, reason) 
                VALUES (%s, %s, %s, %s, %s)
            """
            execute_query(query, (employee_id, leave_type, start_date, end_date, reason), fetch=False)
            
            self.speak("您的请假申请已提交，请等待审批。")
        
        except Exception as e:
            logger.error(f"Error handling leave request: {e}")
            self.speak("处理请假请求时出现错误，请稍后再试。")
    
    def _handle_policy_inquiry(self, text):
        """
        Handle a policy inquiry command.
        
        Args:
            text (str): The recognized text containing the policy inquiry.
        """
        try:
            # Determine which policy the user is asking about
            policy_category = None
            if any(keyword in text for keyword in ['考勤', '打卡', '上班', '下班']):
                policy_category = 'attendance'
            elif any(keyword in text for keyword in ['请假', '休假', '病假', '事假']):
                policy_category = 'leave'
            elif any(keyword in text for keyword in ['加班', '工资', '薪资']):
                policy_category = 'general'
            
            # If we can't determine the category, ask for clarification
            if policy_category is None:
                self.speak("您想了解哪方面的制度？考勤制度、请假制度还是加班制度？")
                return
            
            # Check Redis cache first
            cache_key = f"policy:{policy_category}"
            if self.redis and self.redis.exists(cache_key):
                policy_content = self.redis.get(cache_key).decode('utf-8')
                logger.info(f"Retrieved policy from cache: {cache_key}")
            else:
                # Query the database for the policy
                query = "SELECT title, content FROM company_policies WHERE category = %s"
                results = execute_query(query, (policy_category,))
                
                if not results:
                    self.speak("抱歉，未找到相关制度信息。")
                    return
                
                policy = results[0]
                policy_content = f"{policy['title']}：{policy['content']}"
                
                # Cache the result in Redis for 1 hour
                if self.redis:
                    self.redis.setex(cache_key, 3600, policy_content)
            
            # Speak the policy content
            self.speak(policy_content)
        
        except Exception as e:
            logger.error(f"Error handling policy inquiry: {e}")
            self.speak("查询制度信息时出现错误，请稍后再试。")
    
    def _provide_help(self):
        """Provide help information about the system."""
        help_text = """
        智慧考勤系统使用说明：
        1. 打卡功能：请对着摄像头，系统会自动进行人脸识别并记录您的考勤。
        2. 请假功能：您可以通过语音申请请假，例如"我要请3天病假"。
        3. 制度查询：您可以通过语音查询公司制度，例如"查询考勤制度"。
        如需更多帮助，请联系管理员。
        """
        self.speak(help_text)
    
    def _get_leave_type_name(self, leave_type):
        """
        Get the Chinese name for a leave type.
        
        Args:
            leave_type (str): The leave type code.
            
        Returns:
            str: The Chinese name for the leave type.
        """
        leave_types = {
            'sick': '病假',
            'personal': '事假',
            'vacation': '年假',
            'other': '其他假期'
        }
        return leave_types.get(leave_type, '假期')

# For testing
if __name__ == "__main__":
    def command_callback(text):
        print(f"Command received: {text}")
    
    assistant = VoiceAssistant()
    assistant.start(command_callback=command_callback)
    
    # Speak a welcome message
    assistant.speak("欢迎使用智慧考勤系统，请问有什么可以帮您？")
    
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        assistant.stop()
        print("Voice assistant stopped")